/* Copyright (c) 2009-2010 Jing Zhao, Emil Kleijn, Xaveer Leijtens
 *
 * This file is part of libMask.
 *
 * libMask is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * libMask is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with libMask.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "mask.h"

extern void half_1x(double, double, double, double, double);

/* Function draws a one input MMI reflector with specified offset, and
 * angled corners. reflecting plane is 45 degree.
 * If the current pointer points to the right, the MMI is as shown, with
 * offset 1,2 as below (zero offset is in center, positive moves in the
 * direction shown):
 *                
 *        ________/\
 *       /          \
 *   ->   o  +       : (CP not changed by this function)
 *   cp  \___V____  / 
 *                \/ 
 */
void reflector_1x0(double lmmi,	/* Length of the MMI */
  double wmmi,			/* Width of the MMI */
  double x,			/* extended length */
  double wwg,			/* Width of input/output waveguide */
  double o,			/* Waveguide offsets (relative to MMI center) */
  double angle			/* Angle of corners: RAD(90) is normal MMI */
  )
{
  /*push_cp();
  half_1x(2 * (lmmi - x - wmmi / 2), wmmi, wwg, o, angle);
  offset(-o);
  skip(lmmi - x - wmmi / 2);
  rotate(RAD(45));
  skip(-(2 * x + wmmi) / sqrt(2) / 2);
  sw((2 * x + wmmi) / sqrt(2), (2 * x + wmmi) / sqrt(2));
  pop_cp();*/
  
  // reflector_1x0 is a specific case of a butterfly reflector:
  push_cp();
  butterfly_reflector_2x0( lmmi, wmmi, 0, x, wwg, o, o, 0, angle);
  pop_cp();
}

/* Function draws a one input MMI reflector with specified offset, and
 * angled corners. reflecting plane is 45 degree. If the current pointer
 * points to the right, the MMI is as shown, with offset 1,2 as below (zero
 * offset is in center, positive moves in the direction shown):
 *                
 *          ________/\
 *  cp _\  /          \   1
 *      /  \ o  -      \
 *                      :
 *  cp /__ /    +      /  
 *     \   \___V____  /   2
 *                  \/ 
 */
void reflector_2x0(double lmmi,	/* Length of the MMI */
  double wmmi,			/* Width of the MMI */
  double x,			/* extended length */
  double wwg,			/* Width of input/output waveguide */
  double o1,			/* Waveguide offset (relative to MMI center) */
  double o2,			/* Waveguide offset (relative to MMI center) */
  double angle			/* Angle of corners: RAD(90) is normal MMI */
  )
{
  /*push_cp();
  half_1x(2 * (lmmi - x - wmmi / 2), wmmi, wwg, o1, angle);
  skip(lmmi - x - wmmi / 2);
  offset(-o1);
  rotate(RAD(45));
  skip(-(2 * x + wmmi) / sqrt(2) / 2);
  sw((2 * x + wmmi) / sqrt(2), (2 * x + wmmi) / sqrt(2));
  pop_cp();
  offset(-o1 + o2);
  half_1x(2 * (lmmi - x - wmmi / 2), wmmi, wwg, o2, angle);
  rotate(RAD(180));*/
  
  //reflector_2x0 is a specific case of a butterfly reflector:
  butterfly_reflector_2x0(lmmi, wmmi, 0, x, wwg, o1, o2, 0, angle);
}


/*  
    This is the specific butterfly reflector function. For normal use
    call the butterfly_reflector_2x0(...) function. The specific
    function has an extra parameter 'margin' which expands the outline
    of the device by 'margin' metres.

    dW_W=0    dW_W<0      dW_W>0
    ____                    /\
   |    |     |\/|         |  |
   |____|     |/\|          \/


      o1=o2                     o1<o2                   o1>o2
  |'-._       _/\           |'-._       _/\         |'-._      /\
->|    '-._.-'   \          |    '-._.-'   \      ->|    '-._.'  \
  |               \       ->|              /        |             \
  |               /         |             /       <-|              \
<-|    _.-'-._   /        <-|    _.-'-.  /          |    _.-'-._   /  
  |_.-'       '\/           |_.-'      \/           |_.-'       '\/  
*/
void butterfly_reflector_2x0_s(
  double lmmi,	/* Length of the MMI */
  double wmmi,	/* Width of the MMI */
  double dW_W,  /* Normalized butterfly coefficient dW/wmmi */
  double x,			/* extended length */
  double wwg,		/* Width of input/output waveguide */
  double o1,		/* Waveguide offset (relative to MMI center) */
  double o2,		/* Waveguide offset (relative to MMI center) */
  double point_offset,  /* Offset of the mirror point (relative of MMI centre) */
  double angle,	/* Angle of corners: RAD(90) is normal MMI */
  double margin /* Will expand the outline of the device with this amount*/
  )
{
  double dW = dW_W*wmmi;
  double F=fabs(point_offset)/(1-2*dW/lmmi) - (wmmi/2+dW+2*x-lmmi/2)/(1-2*dW/lmmi);
  double G=-fabs(point_offset)/(1-2*dW/lmmi) - (wmmi/2+dW+2*x-lmmi/2)/(1-2*dW/lmmi);
  double signum, delta;
  
  double Lt1a, Lt1b, Lt2a, Lt2b;
  double W1a,W1b,W2a,W2b;
  double verysmall = 1e-12;
  
  struct pointer pos;
  
  Lt1a= (wmmi/2-fabs(o1)-wwg/2)  / (tan(angle)-2*dW/lmmi);
  Lt2a= (wmmi/2-fabs(o2)-wwg/2)  / (tan(angle)-2*dW/lmmi);
  if(Lt1a < verysmall)
    Lt1a=0.0;
  if(Lt2a < verysmall)
    Lt2a=0.0;
  
  Lt1b = fmax(Lt1a,Lt2a) - Lt1a;
  Lt2b = fmax(Lt1a,Lt2a) - Lt2a;
  if(Lt1b < verysmall)
    Lt1b=0.0;
  if(Lt2b < verysmall)
    Lt2b=0.0;
  
  W1a=wmmi -2*fabs(o1)+2*(2*dW/lmmi) * Lt1a + 2*margin*(1+dW/lmmi);
  W1b=W1a + (tan(angle) + 2*dW/lmmi) * Lt1b;
  W2a=wmmi -2*fabs(o2)+2*(2*dW/lmmi) * Lt2a + 2*margin*(1+dW/lmmi);
  W2b=W2a + (tan(angle) + 2*dW/lmmi) * Lt2b;
    
  //Move to lateral device centre
  offset(-o1);
  push_cp();
    
  //Remember centre position
  pos=cp;
  
  //Taper for first input wg
  offset(o1);
  taper(Lt1a, wwg+2*margin, W1a);
  taper_angle(Lt1b,  atan( tan(angle) - (W1b-W1a)/(2*Lt1b)), W1a, W1b);
  
  cp=pos;
  
  //Taper for second input wg
  offset(o2);
  taper(Lt2a, wwg+2*margin, W2a);
  taper_angle(Lt2b, -atan( tan(angle) - (W2b-W2a)/(2*Lt2b)), W2a, W2b);
  
  cp=pos;
  skip(fmax(Lt1a,Lt2a));
  
  //MMI body
  taper(lmmi/2-fmax(Lt1a,Lt2a), wmmi+2*margin*(1+dW/lmmi)+4*dW*fmax(Lt1a,Lt2a)/lmmi, wmmi+2*margin+2*dW);
  taper(F, wmmi+2*margin+2*dW, wmmi+2*dW-4*dW/lmmi*F+2*margin);

  //Reflector
  delta=lmmi/4-x/2-F/2;
  //point_offset > 0.0 ? signum=1 : signum=-1;
  signum = ((point_offset > 0.0) ? 1 : -1);
  org(lmmi/2+G+x-delta,signum*(-wmmi/2-dW+G*2*dW/lmmi-x+delta), signum*RAD(45),NOFLIP);
  skip(-0.5*sqrt(2)*margin);
  sw(sqrt(2)*(lmmi/2-x-G)+sqrt(2)*margin,sqrt(2)*(lmmi/2-x-F)+sqrt(2)*margin);
  
  //Move cp to output wg
  pop_cp();
  offset(o2);
  rotate( RAD(180) );
}

void butterfly_reflector_2x0(
  double lmmi,	/* Length of the MMI */
  double wmmi,	/* Width of the MMI */
  double dW_W,  /* Normalized butterfly coefficient dW/wmmi */
  double x,			/* extended length */
  double wwg,		/* Width of input/output waveguide (not needed yet)*/
  double o1,		/* Waveguide offset (relative to MMI center) (not needed yet)*/
  double o2,		/* Waveguide offset (relative to MMI center) (not needed yet)*/
  double point_offset,  /* Offset of the mirror point (relative of MMI centre) */
  double angle	/* Angle of corners: RAD(90) is normal MMI (not supported yet) */
  )
{
  butterfly_reflector_2x0_s(lmmi, wmmi, dW_W, x, wwg, o1, o2, point_offset, angle, 0.0);
}
